﻿using NHibernate;
using System;
using System.Collections.Generic;
using System.Data;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using YYSite.Common.Logging;

namespace YYSite.Common.NHibernate
{
    public interface ITransactionManager 
    {
        void Demand();
        void RequireNew();
        void RequireNew(IsolationLevel level);
        void Cancel();

        ISession GetSession();
    }

    public class TransactionManager : ITransactionManager, IDisposable
    {
  

        private ISession _session;
        private ISessionFactory sessionFactory;

        public TransactionManager(INHFluentConfiguration configuration)
        {
            sessionFactory = configuration.GetSessionFactory();
            Logger = NullLogger.Instance;
            IsolationLevel = IsolationLevel.ReadCommitted;
        }

        public ILogger Logger { get; set; }
        public IsolationLevel IsolationLevel { get; set; }

        public ISession GetSession()
        {
            Demand();
            return _session;
        }
        public void Demand()
        {
            EnsureSession(IsolationLevel);
        }

        public void RequireNew()
        {
            RequireNew(IsolationLevel);
        }

        public void RequireNew(IsolationLevel level)
        {
            DisposeSession();
            EnsureSession(level);
        }

        public void Cancel()
        {
            // IsActive is true if the transaction hasn't been committed or rolled back
            if (_session != null && _session.Transaction.IsActive)
            {
                Logger.Debug("Rolling back transaction");
                _session.Transaction.Rollback();
                DisposeSession();
            }
        }

        public void Dispose()
        {
            DisposeSession();
        }

        private void DisposeSession()
        {
            if (_session != null)
            {

                try
                {
                    // IsActive is true if the transaction hasn't been committed or rolled back
                    if (_session.Transaction.IsActive)
                    {
                        Logger.Debug("Committing transaction");
                        _session.Transaction.Commit();
                    }
                }
                finally
                {
       

                    Logger.Debug("Disposing session");
                    _session.Close();
                    _session.Dispose();
                    _session = null;
                }
            }
        }

        private void EnsureSession(IsolationLevel level)
        {
            if (_session != null)
            {
                return;
            }

          
            Logger.Debug("Opening NHibernate session");
            _session = sessionFactory.OpenSession();
            _session.BeginTransaction(level);

        }

        
    }
}
